﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace Bookvar.UI
{
    public static class PanelLayoutAnimator
    {
        #region OldTop

        public static readonly DependencyProperty OldTopProperty =
            DependencyProperty.RegisterAttached("OldTop", typeof(double), typeof(PanelLayoutAnimator), new FrameworkPropertyMetadata(default(double)));

        public static double GetOldTop(DependencyObject obj)
        {
            return (double) obj.GetValue( OldTopProperty );
        }

        public static void SetOldTop(DependencyObject obj, double value)
        {
            obj.SetValue( OldTopProperty, value );
        }

        #endregion

        #region OldLeft

        public static readonly DependencyProperty OldLeftProperty =
            DependencyProperty.RegisterAttached("OldLeft", typeof(double), typeof(PanelLayoutAnimator), new FrameworkPropertyMetadata(default(double)));

        public static double GetOldLeft(DependencyObject obj)
        {
            return (double)obj.GetValue(OldLeftProperty);
        }

        public static void SetOldLeft(DependencyObject obj, double value)
        {
            obj.SetValue(OldLeftProperty, value);
        }

        #endregion

        #region CompleteCallback

        public static readonly DependencyProperty CompleteCallbackProperty =
            DependencyProperty.RegisterAttached("CompleteCallback", typeof(CompleteCallback), typeof(PanelLayoutAnimator), new FrameworkPropertyMetadata(default(CompleteCallback)));

        internal static CompleteCallback GetCompleteCallback(DependencyObject obj)
        {
            return (CompleteCallback)obj.GetValue(CompleteCallbackProperty);
        }

        internal static void SetCompleteCallback(DependencyObject obj, CompleteCallback value)
        {
            obj.SetValue(CompleteCallbackProperty, value);
        }
	
        #endregion

        internal delegate void CompleteCallback();

        internal static void Animate( MindMapPanel panel, CompleteCallback completeCallback )
        {
            List<TopicContentPresenter> childrenToAnimate = new List<TopicContentPresenter>();
            foreach (TopicContentPresenter presenter in panel.ChildPresenters)
            {
                if ( !presenter.Topic.IsMainTopic )
                {
                    childrenToAnimate.Add( presenter );
                }
            }
            foreach ( TopicContentPresenter child in childrenToAnimate )
            {
                TranslateTransform newTransform = new TranslateTransform();
                child.RenderTransform = newTransform;

                SetOldLeft( child, Canvas.GetLeft( child ) );
                SetOldTop( child, Canvas.GetTop( child ) );
                SetCompleteCallback( child, completeCallback );

                AddHandlers( child );
            }
        }

        private static void AddHandlers( TopicContentPresenter presenter )
        {
            DependencyPropertyDescriptor leftPropertyDescriptor =
                DependencyPropertyDescriptor.FromProperty( Canvas.LeftProperty, typeof( TopicContentPresenter ) );
            if (leftPropertyDescriptor != null)
            {
                leftPropertyDescriptor.AddValueChanged( presenter, OnLeftChanged );
            }
            DependencyPropertyDescriptor topPropertyDescriptor =
                DependencyPropertyDescriptor.FromProperty( Canvas.TopProperty, typeof( TopicContentPresenter ) );
            if (topPropertyDescriptor != null)
            {
                topPropertyDescriptor.AddValueChanged( presenter, OnTopChanged);
            }
        }

        private static void RemoveLeftHandler( TopicContentPresenter presenter )
        {
            DependencyPropertyDescriptor leftPropertyDescriptor =
                DependencyPropertyDescriptor.FromProperty( Canvas.LeftProperty, typeof( TopicContentPresenter ) );
            if (leftPropertyDescriptor != null)
            {
                leftPropertyDescriptor.RemoveValueChanged( presenter, OnLeftChanged );
            }
        }

        private static void RemoveTopHandler( TopicContentPresenter presenter )
        {
            DependencyPropertyDescriptor topPropertyDescriptor =
                DependencyPropertyDescriptor.FromProperty( Canvas.TopProperty, typeof( TopicContentPresenter ) );
            if (topPropertyDescriptor != null)
            {
                topPropertyDescriptor.RemoveValueChanged( presenter, OnTopChanged);
            }
        }

        private static void OnLeftChanged( object sender, EventArgs e )
        {
            TopicContentPresenter presenter = (TopicContentPresenter) sender;

            TranslateTransform transform = (TranslateTransform) presenter.RenderTransform;
            DoubleAnimation animation =
                MakeAnimation( GetOldLeft( presenter ) - Canvas.GetLeft( presenter ) );
            transform.BeginAnimation( TranslateTransform.XProperty, animation );

            RemoveLeftHandler( presenter );
        }

        private static void OnTopChanged( object sender, EventArgs e )
        {
            TopicContentPresenter presenter = (TopicContentPresenter) sender;

            TranslateTransform transform = (TranslateTransform) presenter.RenderTransform;
            DoubleAnimation animation =
                MakeAnimation( GetOldTop( presenter ) - Canvas.GetTop( presenter ) );
            animation.Completed += delegate
            {
                object callback = presenter.ReadLocalValue( CompleteCallbackProperty );
                if ( callback != DependencyProperty.UnsetValue )
                {
                    CompleteCallback completeCallback = callback as CompleteCallback;
                    if ( completeCallback != null )
                    {
                        completeCallback();
                    }

                    foreach (TopicContentPresenter child in presenter.Owner.ChildPresenters)
                    {
                        child.SetValue( CompleteCallbackProperty, DependencyProperty.UnsetValue );
                    }

                    
                }
            };
            transform.BeginAnimation( TranslateTransform.YProperty, animation );
            

            RemoveTopHandler( presenter );
        }

        // Note: this can be taken from a resource
        private static DoubleAnimation MakeAnimation( double start )
        {
            DoubleAnimation animation =
                new DoubleAnimation( start, 0d, new Duration( TimeSpan.FromMilliseconds( 2000 ) ) );
            animation.AccelerationRatio = 0.6;
            return animation;
        }
    }
}